/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package PhysicCollection;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.net.URL;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;

/**
 *
 * @author danh.ngothanh
 */
public class ShootingGame2DDemo extends JPanel implements Runnable, MouseListener, MouseMotionListener{

    private int mouse_x, mouse_y;

    //mc
    private int mc_pos_x, mc_pos_y;
    private static int MC_MOVE_SPEED = 2;
    private static int MC_RADIUS = 20;
    private boolean keyuppressed, keydownpressed, keyleftpressed, keyrightpressed;
    private int user_score = 0;
    private int user_lifes = 5;
    private int game_level = 0;

    //weapon level
    private static int NORMAL_LEVEL = 1;
    private static int MEGA_LEVEL = 2;
    private static int SUPER_LEVEL = 3;
    


    //gun
    private int gun_x, gun_y;
    private double gunangle;
    private int gun_level = NORMAL_LEVEL;
    
    

    //mc bullet
    private boolean gun_shooting = false;
    private ArrayList<Bullet> bullet_arraylist;
    private int i_delay_beetween_2_bullet = 3;
    
    
    

    //mc missile
    private boolean missile_shooting = false;
    private ArrayList<HomingMissile> missile_arraylist;
    private int missle_shot_avalable = 10;
    private int max_missile_per_time = 10;
    private int missile_shot_time = 1;
    private AffineTransform at = new AffineTransform();
    Graphics2D g2d;
    URL rocketimgurl = this.getClass().getResource("/resources/rocket.gif");
    Image im = this.getToolkit().getImage(rocketimgurl);

    private int missile_level = NORMAL_LEVEL;

    //enemy
    private ArrayList<Enemy> enemy_list = new ArrayList<Enemy>();


    //design   
    //item
    /*
     * increase missle count per shot (2x)
     * level 1: 1 shot line
     * level 2: 2 gun 2 shot line
     * level max: 3 gun 3 shot line
     * increase gun shot line count (2x)     
     * level 1: 10 missile 1 time
     * level 2: 20 missile 1 time
     * level max: 20 missile 1 time
     */


    
    public ShootingGame2DDemo(){
        mouse_x = 0;
        mouse_y = 0;
        mc_pos_x = 610;
        mc_pos_y = 440;
        bullet_arraylist = new ArrayList<Bullet>();
        missile_arraylist = new ArrayList<HomingMissile>();
        enemy_list = new ArrayList<Enemy>();
        gun_x = mc_pos_x;
        gun_y = mc_pos_y;
        keyuppressed = false;
        keydownpressed = false;
        keyleftpressed = false;
        keyrightpressed = false;
        enemy_list.add(new Enemy(this, 1000, 500, 0));
    }

    private class Enemy{
        private int pos_x, pos_y;
        private int health = 0;
        private int TYPE_EASY = 0;
        private int TYPE_NORMAL = 1;
        private int TYPE_HARD = 2;
        private int TYPE_BOSS = 3;
        private int type = TYPE_EASY;
        private int ENEMY_RADIUS = 10;
        private boolean is_locked_by_missile = false;
        private ShootingGame2DDemo parent;
        private boolean tmp_direction = false;

        
        public Enemy(ShootingGame2DDemo parent, int pos_x, int pos_y, int enemy_type){
            this.parent = parent;
            this.pos_x = pos_x;
            this.pos_y = pos_y;
            type = enemy_type;
        }

        public void relocation(int mc_x, int mc_y){
            if(this.type == TYPE_EASY){

                //sample                
                if(tmp_direction){
                    pos_y ++;
                    if(pos_y > parent.getHeight() - ENEMY_RADIUS){
                        tmp_direction = false;                        
                    }
                }else{
                    pos_y --;
                    if(pos_y < ENEMY_RADIUS){                        
                        tmp_direction = true;                        
                    }
                }
                
            }
        }

        public int getPosX(){
            return pos_x;
        }

        public int getPosY(){
            return pos_y;
        }

        public int getRadius(){
            return ENEMY_RADIUS;
        }

        public void setLockbyMissile(boolean islock){
            is_locked_by_missile = islock;
        }
        public boolean isLockedbyMissile(){
            return is_locked_by_missile;
        }
        public void finalize(){
            pos_x = 0;
            pos_y = 0;
            health = 0;
            type = 0;
            is_locked_by_missile = false;
            TYPE_NORMAL = 0;
            TYPE_HARD = 0;
            TYPE_BOSS = 0;
            try {
                super.finalize();
            } catch (Throwable ex) {
                Logger.getLogger(ShootingGame2DDemo.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }
    public void init(){
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    private void Add_New_Bullet(){
        bullet_arraylist.add(new Bullet(gun_x, gun_y, mouse_x, mouse_y));
        bullet_arraylist.get(bullet_arraylist.size() - 1).setSpeed(10);
    }

    private void Update_Bullet_List(){
        if(!bullet_arraylist.isEmpty()){
            for(int i = 0; i < bullet_arraylist.size(); i ++){
                if(bullet_arraylist.get(i).isHitTarget(enemy_list.get(0).getPosX(), enemy_list.get(0).getPosY(), enemy_list.get(0).getRadius())){
                    user_score += 10;
                }
                if((bullet_arraylist.get(i).isHitTarget(enemy_list.get(0).getPosX(), enemy_list.get(0).getPosY(), enemy_list.get(0).getRadius())) || (bullet_arraylist.get(i).checkvisible() != true)){
                    try {
                        bullet_arraylist.get(i).finalize();
                    } catch (Throwable ex) {
                    }
                    bullet_arraylist.remove(i);
                }
            }
            try{
                for(int i = 0; i < bullet_arraylist.size(); i ++){
                    bullet_arraylist.get(i).relocation();
                }
            }catch(Exception e){}
             
        }
    }
    private void Create_Missile_Shot(){
        int current_missile_x, current_missile_y;
        double current_missile_angle = 0;        
        for(int i = 0; i < max_missile_per_time; i ++){
            current_missile_angle += (2*Math.PI)/max_missile_per_time;
            current_missile_x = (int)(mc_pos_x + 25 * Math.sin(current_missile_angle));
            current_missile_y = (int)(mc_pos_y + 25 * Math.cos(current_missile_angle));
            missile_arraylist.add(new HomingMissile(current_missile_x, current_missile_y, mouse_x, mouse_y, 0));            
        }
        current_missile_angle = 0;
        for(int i = missile_arraylist.size()-1 ; i >= missile_arraylist.size() - max_missile_per_time; i--){
            current_missile_angle += (2*Math.PI)/max_missile_per_time;
            missile_arraylist.get(i).setMissileSpeed(2);
            missile_arraylist.get(i).setMissileCurrentAngle(current_missile_angle - Math.PI);
        }
    }

    private void Missiles_Update(){
        if(missile_arraylist.size() > 0)
            for(int i = missile_arraylist.size() - 1; i >=0 ; i--){
                if(missile_arraylist.get(i).isHitTarget(enemy_list.get(0).getPosX(), enemy_list.get(0).getPosY(), enemy_list.get(0).getRadius())){
                    user_score += 5;
                    missile_arraylist.get(i).finalize();
                    missile_arraylist.remove(i);
                }
            }
        for(int i = missile_arraylist.size() - 1; i >=0 ; i--){
            missile_arraylist.get(i).relocation(enemy_list.get(0).getPosX(), enemy_list.get(0).getPosY());
        }
    }

    private void UpdateMCPosition(){
        if(keyuppressed){
            mc_pos_y -= MC_MOVE_SPEED;
            if(mc_pos_y - MC_RADIUS < 0){
                mc_pos_y = MC_RADIUS;
            }
        }
        if(keydownpressed){
            mc_pos_y += MC_MOVE_SPEED;
            if(mc_pos_y + MC_RADIUS > getHeight()){
                mc_pos_y = getHeight() - MC_RADIUS;
            }
        }
        if(keyrightpressed){
            mc_pos_x += MC_MOVE_SPEED;
            if(mc_pos_x + MC_RADIUS > getWidth()){
                mc_pos_x = getWidth() - MC_RADIUS;
            }
        }
        if(keyleftpressed){
            mc_pos_x -= MC_MOVE_SPEED;
            if(mc_pos_x - MC_RADIUS < 0){
                mc_pos_x = MC_RADIUS;
            }
        }
    }

    private void UpdateEnemies(){
        for(int i = 0; i < enemy_list.size(); i ++){
            enemy_list.get(i).relocation(mc_pos_x, mc_pos_y);
        }
    }

    public void run() {
         while(true){            
            try{
                Thread.sleep(5);
            }
            catch(Exception e){}

            UpdateMCPosition();
            UpdateEnemies();

            //recalculate gun angle
            gunangle = Math.atan2(mouse_x - mc_pos_x, mouse_y - mc_pos_y);
            gun_x = (int)(mc_pos_x + 20 * Math.sin(gunangle));//toa do x theo cos moi dung
            gun_y = (int)(mc_pos_y + 20 * Math.cos(gunangle));//toa do y theo sin moi dung

            //calculate bullet
            if(gun_shooting){
                if(i_delay_beetween_2_bullet > 0)
                    i_delay_beetween_2_bullet --;
                else{
                    Add_New_Bullet();
                    i_delay_beetween_2_bullet = 3;
                }
            }
            Update_Bullet_List();

            Missiles_Update();
            
            if(missile_arraylist.isEmpty() && missile_shooting){
                missile_shooting = false;
            }
                
            
         repaint();
         }
    }

     @Override
    public void paint(Graphics g){
        g.setColor(new Color(200, 200, 200));
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.BLACK);
        //debug string
        g.drawString("Missile Count: "+ missile_arraylist.size(), 5, 15);
        g.drawString("Missile Fire Avalable: "+ missle_shot_avalable, 5, 30);
        g.drawString("Game Level: "+ game_level, 5, 45);
        g.drawString("Score: "+ user_score, 5, 60);
        g.drawLine(gun_x, gun_y, mc_pos_x, mc_pos_y);
        try{
        for(int i = 0; i < bullet_arraylist.size(); i ++)
            g.fillRect(bullet_arraylist.get(i).getBulletX() - 1, bullet_arraylist.get(i).getBulletY() - 1, 2, 2);
        }catch(Exception e){}
        g.fillOval(mc_pos_x - MC_RADIUS/2, mc_pos_y - MC_RADIUS/2, MC_RADIUS, MC_RADIUS);
        g2d = (Graphics2D) g;
        for(int i= 0; i < missile_arraylist.size(); i ++){
            at = g2d.getTransform();
            g2d.translate(missile_arraylist.get(i).getMissilePosX(), missile_arraylist.get(i).getMissilePosY());
            g2d.rotate(missile_arraylist.get(i).getMissileCurrentAngle());
            g2d.drawImage(im, -im.getWidth(this)/2, -im.getHeight(this)/2, this);
            g2d.setTransform(at);
        }


        //draw lock target icon
//        g.drawLine(120, 100, 100, 100);
//        g.drawLine(100, 100, 100, 120);
//
//        g.drawLine(140, 100, 160, 100);
//        g.drawLine(160, 120, 160, 100);
//
//        g.drawLine(100, 140, 100, 160);
//        g.drawLine(100, 160, 120, 160);
//
//        g.drawLine(160, 140, 160, 160);
//        g.drawLine(160, 160, 140, 160);


        //draw enemies
        g.setColor(Color.RED);
        for(int i = 0; i < enemy_list.size(); i ++){
            g.fillOval(enemy_list.get(i).getPosX() - enemy_list.get(i).getRadius(), enemy_list.get(i).getPosY() - enemy_list.get(i).getRadius(), enemy_list.get(i).getRadius(), enemy_list.get(i).getRadius());
        }
    }

    public void mouseClicked(MouseEvent e) {
        
    }

    public void mousePressed(MouseEvent e) {
        mouse_x = e.getX();
        mouse_y = e.getY();
        if(e.getButton() == MouseEvent.BUTTON1){
            gun_shooting = true;
        }
        if(e.getButton() == MouseEvent.BUTTON3){
            if(missle_shot_avalable > 0){
                Create_Missile_Shot();
                missle_shot_avalable --;
            }
            //cheat
//            if(missle_shot_avalable == 0 && missile_arraylist.isEmpty()){//cheat not limit missile number
                missle_shot_avalable = 10;
//            }
        }        
    }

    public void mouseReleased(MouseEvent e) {
        if(e.getButton() == MouseEvent.BUTTON1){
            gun_shooting = false;
        }
    }

    public void mouseEntered(MouseEvent e) {
        
    }

    public void mouseExited(MouseEvent e) {
        
    }   

    public void mouseDragged(MouseEvent e) {
        mouse_x = e.getX();
        mouse_y = e.getY();
    }

    public void mouseMoved(MouseEvent e) {
        mouse_x = e.getX();
        mouse_y = e.getY();
    }

    public void keyPressed(KeyEvent e){
        if(e.getKeyCode() == KeyEvent.VK_A){
           keyleftpressed = true;
        }
            
        if(e.getKeyCode() == KeyEvent.VK_D){
            keyrightpressed = true;
        }

        if(e.getKeyCode() == KeyEvent.VK_W){
           keyuppressed = true;
        }
            
        if(e.getKeyCode() == KeyEvent.VK_S){
            keydownpressed = true;
       }            
            
    }
    public void keyReleased(KeyEvent e){
        if(e.getKeyCode() == KeyEvent.VK_A){
           keyleftpressed = false;
        }

        if(e.getKeyCode() == KeyEvent.VK_D){
            keyrightpressed = false;
        }

        if(e.getKeyCode() == KeyEvent.VK_W){
           keyuppressed = false;
        }

        if(e.getKeyCode() == KeyEvent.VK_S){
            keydownpressed = false;
       }
    }

}

//@todo:
/*
 * mỗi enemy có thể bị lock bởi 1 hay nhiều tên lửa, nếu số enemy lớn hơn số tên lửa: mỗi tên lữa lock 1 enemy, ngược lại: các tên lửa lock toàn
 * bộ target, nếu tên lửa nào dư thì lock các target cũ theo thứ tự, hoặc nếu enemy nào chưa chết thì chuyển hướng về enemy đó
 * làm cho tên lửa thông minh hơn, có thể tạo path mới để có thể đến được mục tiêu đứng yên
 * Làm cái lock target giống chiêu mean lock của con nam châm pokemon
 * làm cho các tên lửa bay thẳng khi không còn mục tiêu để bắn nữa, finalize missile khi ra khoi man hinh, cac missile sau khi mất điều khiển sẽ
 * trở lại và lock có target mới
 * missile bay tới mục tiêu, nhưng nếu trên đường bay mà đụng phải bất cứ enemy nào cũng sẽ nổ
 * Làm các bullet tách ra để thấy được hiệu ứng di chuyển của bullet chứ đừng để bullet sau lấy vị trí của bullet trước thì sẽ không thấy được hiệu ứng di chuyển
 */